package com.plian.system.service.sys.seal.impl;

import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import com.plian.Tools.*;
import com.plian.Tools.pagedata.PageData;
import com.plian.system.constant.sys.FormStatusConstant;
import com.plian.system.dao.sys.file.FileDao;
import com.plian.system.dao.sys.per.PerUserDao;
import com.plian.system.entity.sys.SealApply;
import com.plian.system.mapper.sys.SealApplyMapper;
import com.plian.system.model.CommonCode;
import com.plian.system.model.ListResult;
import com.plian.system.mybatis.base.BaseFlowService;
import com.plian.system.mybatis.base.BaseServiceImpl;
import com.plian.system.mybatis.search.SearchEntity;
import com.plian.system.mybatis.search.SearchParamEntiy;
import com.plian.system.mybatis.support.Condition;
import com.plian.system.mybatis.support.Query;
import com.plian.system.pdf.OutPdf;
import com.plian.system.service.sys.file.FileService;
import com.plian.system.service.sys.seal.ISealApplyService;
import com.plian.system.service.wf.FormWorkflowService;
import com.plian.system.vo.sys.SealApplyVO;
import com.plian.system.wrapper.sys.SealApplyWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.lang3.StringUtils;
import org.flowable.ui.common.service.exception.BadRequestException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.*;
import java.util.*;

import static com.plian.system.constant.sys.FormStatusConstant.UNREVIEWED;
import static com.plian.system.constant.sys.FormTypeConstant.SYS_SEAL_APPLY;
import static com.plian.system.pdf.OutPdf.processDate;

/**
 * <p>
 * 用印申请 服务实现类
 * </p>
 *
 * @author husong
 * @since 2023-03-18 13:09:29
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SealApplyServiceImpl extends BaseServiceImpl<SealApplyMapper, SealApply> implements ISealApplyService, BaseFlowService {

    private final SealApplyMapper sealApplyMapper;
    private final SealApplyWrapper sealApplyWrapper;
    private final FormWorkflowService formWorkflowService;
    private final FileService fileService;
    private final PerUserDao perUserDao;
    private final FileDao fileDao;


    @Override
    public ListResult<SealApplyVO> findAll(Query query) {
        ListResult<SealApplyVO> listResult = new ListResult<>(CommonCode.SUCCESS);
        List<SearchEntity> entityList = query.getSearch();

        if (query.getAscs() == null && query.getDescs() == null) {
            query.setDescs("create_time");
        }

        QueryWrapper<SealApply> queryWrapper = SearchParamEntiy.getQueryWrapper(
                Condition.getQueryWrapper(new SealApply()), entityList
        );

        try {
            List<PageData> pageDatas = perUserDao.queryPerUser(TokenUtil.getTokenUserId());
            // 拥有印章管理员的角色可以看到全部数据 否则只能看到自己的数据
            if (pageDatas.stream().noneMatch(pd -> pd.getString("groupName").equals("印章管理员"))) {
                queryWrapper.eq("create_user", TokenUtil.getTokenUserId());
            }
        } catch (Exception e) {
            throw new BadRequestException("获取用户角色信息错误");
        }
        IPage<SealApply> page = page(Condition.getPage(query), queryWrapper);
        listResult.setList(sealApplyWrapper.entityToVO(page.getRecords()));
        listResult.setTotal((int) page.getTotal());
        return listResult;
    }

    @Override
    public SealApplyVO detail(SealApply sealApply) {
        Assert.notNull(sealApply.getId(), "id不能为空");
        return sealApplyWrapper.entityToVO(sealApplyMapper.selectById(sealApply.getId()));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveOrUpdate(SealApply entity) {

        boolean isSaveFlag = false;
        if (entity.getId() == null) {
            isSaveFlag = true;
            entity.setHandledBy(TokenUtil.getTokenUserId());
            entity.setFormType(String.valueOf(SYS_SEAL_APPLY));
            entity.setCreateCompanyId(TokenUtil.getTokenOrgId());
            entity.setUndertakingOfficeId(Long.parseLong(TokenUtil.getOfficeId()));
        }

        boolean result = super.saveOrUpdate(entity);

        // 上传附件
        if (CollectionUtil.isNotEmpty(entity.getDocList())) {
            if (isSaveFlag) {
                fileService.saveAll(String.valueOf(entity.getId()), entity.getDocList());
            } else {
                fileService.edit(String.valueOf(entity.getId()), entity.getDocList());
            }
        }

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateSignOrFlow(SealApply resource) {
        Assert.notNull(resource.getId(), "id不能为空");
        SealApply sealApply = Optional.ofNullable(getById(resource.getId())).orElseThrow(() -> new BadRequestException("用印申请数据不存在"));

        sealApply.setUndertakingApprovedOpinion(resource.getUndertakingApprovedOpinion());
        sealApply.setUndertakingSignImageId(resource.getUndertakingSignImageId());
        sealApply.setUndertakingApprovedTime(resource.getUndertakingApprovedTime());
        sealApply.setUndertakingApprovedUser(resource.getUndertakingApprovedUser());

        sealApply.setCommitteeApprovedOpinion(resource.getCommitteeApprovedOpinion());
        sealApply.setCommitteeApprovedTime(resource.getCommitteeApprovedTime());
        sealApply.setCommitteeApprovedUser(resource.getCommitteeApprovedUser());
        sealApply.setCommitteeSignImageId(resource.getCommitteeSignImageId());

        sealApply.setUndertakingSignImageId(resource.getUndertakingSignImageId());
        sealApply.setCommitteeSignImageId(resource.getCommitteeSignImageId());

        // 附件
        if (CollectionUtil.isNotEmpty(resource.getDocList())) {
            fileService.edit(String.valueOf(resource.getId()), resource.getDocList());
        }
        return updateById(sealApply);
    }

    @Override
    public File detailPdf(SealApply sealApply) {
        Assert.notNull(sealApply.getId(), "id不能为空");
        SealApplyVO bean = sealApplyWrapper.entityToVO(sealApplyMapper.selectById(sealApply.getId()));

        File file = null;

        try {
            InputStream inputStream = this.getClass().getResourceAsStream("/pdf/sealApply.pdf");
            //通过将文件转换为临时文件进行操作
            File model = File.createTempFile("model", ".png");
            try {
                FileUtils.copyInputStreamToFile(inputStream, model);
            } finally {
                //关闭IO
                IOUtils.closeQuietly(inputStream);
            }

            if (bean != null && model.exists()) {
                Map<String, Object> data = OutPdf.beanToMap(bean);
                // 图片url转base64
                try {
                    PageData doc = fileDao.findbyId(bean.getUndertakingSignImageId());
                    if (Objects.nonNull(doc)){
                        data.put("undertakingSignImageStr", ImageUtils.getImageBase64(doc.getString("filePath") + File.separator + doc.getString("fileName")));
                    }
                    doc = fileDao.findbyId(bean.getCommitteeSignImageId());
                    if (Objects.nonNull(doc)){
                        data.put("committeeSignImageStr", ImageUtils.getImageBase64(doc.getString("filePath") + File.separator + doc.getString("fileName")));
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                // 时间
                data.put("undertakingApprovedTimeStr", Objects.isNull(bean.getUndertakingApprovedTime()) ? "年   月   日" : DateUtil.format(bean.getUndertakingApprovedTime(), "yyyy年MM月dd日"));
                data.put("committeeApprovedTime", Objects.isNull(bean.getCommitteeApprovedTime()) ? "年   月   日" : DateUtil.format(bean.getCommitteeApprovedTime(), "yyyy年MM月dd日"));

                String fileName = model.getPath();
                PdfReader reader = new PdfReader(fileName);
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                /* 将要生成的目标PDF文件名称 */
                PdfStamper ps = new PdfStamper(reader, bos);
                /* 使用中文字体 */
                BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
                ArrayList<BaseFont> fontList = new ArrayList<>();
                fontList.add(bf);

                /* 取出报表模板中的所有字段 */
                AcroFields fields = ps.getAcroFields();
                fields.setSubstitutionFonts(fontList);
                for (String key : data.keySet()) {
                    String value = data.get(key) == null ? null : data.get(key).toString();
                    if (data.get(key) instanceof Date) {
                        value = processDate((Date) data.get(key));
                    }
                    fields.setField(key, value);
                }
                // 多选框
                switch (bean.getType()) {
                    case "155001":
                        fields.setField("toggle_1", "On", true);
                        break;
                    case "155002":
                        fields.setField("toggle_2", "On", true);
                        break;
                    case "155003":
                        fields.setField("toggle_3", "On", true);
                        break;
                }

                /* 必须要调用这个，否则文档不会生成的 */
                ps.setFormFlattening(true);
                ps.close();
                File dir = new File(model.getParent());
                String classFullName = bean.getClass().getName();
                file = File.createTempFile(classFullName.substring(classFullName.lastIndexOf(".")), ".pdf", dir);
                OutputStream fos = new FileOutputStream(file);
                fos.write(bos.toByteArray());
                fos.flush();
                fos.close();
                bos.close();
            }

        } catch (Exception e) {
            log.error(ExceptionUtils.getFullStackTrace(e));
        }
        return file;
    }

    @Override
    public HashMap<String,Object> commit(String id) {
        handleStatus(Long.valueOf(id), FormStatusConstant.FLOW);
        //将需要提交的流程变量返回，用于工作流侧
        return new HashMap<String,Object>();
    }

    @Override
    public Boolean finish(String id) {
        return handleStatus(Long.valueOf(id), FormStatusConstant.FINISH);
    }

    @Override
    public Boolean reject(String id, int formState, String comment) {
        return handleStatus(Long.valueOf(id), formState);
    }

    @Override
    public void goBackToStash(String formId) {
        handleStatus(Long.valueOf(formId), UNREVIEWED);
    }

    @Transactional(rollbackFor = Exception.class)
    public Boolean handleStatus(Long id, int updateStatus) {
        try {
            SealApply sealApply = getById(id);
            /**
             * 设置审批人和审批时间
             */
            if (updateStatus == FormStatusConstant.FINISH) {
                sealApply.setCommitteeApprovedUser(TokenUtil.getTokenUserId());
                Date now = DateUtil.now();
                sealApply.setCommitteeApprovedTime(now);
            }
            sealApply.setStatus(updateStatus);
            updateById(sealApply);
            return true;
        } catch (Exception e) {
            log.error(ExceptionUtils.getFullStackTrace(e));
            return false;
        }
    }

    @Override
    public List<PageData> findByIds(List<String> formIds) {
        LambdaQueryWrapper<SealApply> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(SealApply::getId, Func.toLongList(StringUtils.join(formIds, StringPool.COMMA)));
        List<SealApply> sealApplies = list(queryWrapper);
        List<SealApplyVO> sealApplyVOS = sealApplyWrapper.entityToVO(sealApplies);
        List<PageData> pageDataList = new ArrayList<>();
        try {
            if (CollectionUtil.isNotEmpty(sealApplyVOS)) {
                for (SealApplyVO vo : sealApplyVOS) {
                    PageData pd = new PageData();
                    pd.put("id", vo.getId());
                    // 集团名称
                    pd.put("UNITNAME", vo.getCreateCompanyName());
                    pd.put("APPLICANTNAME", vo.getCreateUserName());
                    pd.put("applicantId", vo.getCreateUser());
                    pd.put("applyOrganizationId", vo.getCreateCompanyId());
                    pd.put("formType", vo.getFormType());
                    // 企业名称
                    pd.put("orgName", vo.getCreateCompanyName());
                    pageDataList.add(pd);
                }
            }

            return pageDataList;
        } catch (Exception e) {
            log.error(ExceptionUtils.getFullStackTrace(e));
        }
        return pageDataList;
    }

    @Override
    public List<Integer> getFormType() {
        return Arrays.asList(SYS_SEAL_APPLY);
    }


//    public static void main(String[] args) {
//        SealApplyVO bean = new SealApplyVO();
//        bean.setTypeName("国资委章");
//        bean.setSubmittedTo("市大数据局");
//        bean.setName("宁波市信息化项目应用汇总表");
//        bean.setUndertakingOfficeName("考核处处室");
//        bean.setHandledByName("kt001");
//        bean.setUndertakingApprovedTime(new Date());
//        bean.setNumber(10);
//        bean.setUndertakingApprovedOpinion("同意");
//        bean.setCommitteeApprovedOpinion("同意");
//
//        bean.setUndertakingSignUrl(ImageUtils.getBase64ByImgUrl("http://rmt-1.rmt.plian.net/2023/03/21/13977652672880330.png"));
//        bean.setCommitteeSignUrl(ImageUtils.getBase64ByImgUrl("http://rmt-1.rmt.plian.net/2023/03/21/13977652672880330.png"));
//
//        Map<String, String> images = new HashMap<>(16);
//        File file = null;
//
//        try {
//            InputStream inputStream = new FileInputStream("/Volumes/Work/delovelop/WorkSpace/yongpai/guozi/GZ_backend/state-owned-system/src/main/resources/pdf/sealApply.pdf");
//            //通过将文件转换为临时文件进行操作
//            File model = File.createTempFile("model", ".png");
//            try {
//                FileUtils.copyInputStreamToFile(inputStream, model);
//            } finally {
//                //关闭IO
//                IOUtils.closeQuietly(inputStream);
//            }
//
//            if (bean != null && model.exists()) {
//                Map<String, Object> data = OutPdf.beanToMap(bean);
//                data.put("undertakingApprovedTimeStr", DateUtil.format(new Date(), "yyyy年MM月dd日"));
//                data.put("committeeApprovedTime",bean.getCommitteeApprovedTime() == null? null : DateUtil.format(new Date(), "yyyy年MM月dd日"));
//
//                String fileName = model.getPath();
//                PdfReader reader = new PdfReader(fileName);
//                ByteArrayOutputStream bos = new ByteArrayOutputStream();
////                 将要生成的目标PDF文件名称
//                PdfStamper ps = new PdfStamper(reader, bos);
////                 使用中文字体
//                BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
//                ArrayList<BaseFont> fontList = new ArrayList<>();
//                fontList.add(bf);
//
////                 取出报表模板中的所有字段
//                AcroFields fields = ps.getAcroFields();
//                fields.setSubstitutionFonts(fontList);
//                for (String key : data.keySet()) {
//                    String value = data.get(key) == null ? null : data.get(key).toString();
//                    if (data.get(key) instanceof Date) {
//                        value = processDate((Date) data.get(key));
//                    }
//                    fields.setField(key, value);
//                }
//                fields.setField("toggle_1", "On", true);
//                fields.setField("toggle_2", "On", true);
//                fields.setField("toggle_3", "On", true);
//
////                 必须要调用这个，否则文档不会生成的
//                ps.setFormFlattening(true);
//                ps.close();
//                File dir = new File(model.getParent());
//                String classFullName = bean.getClass().getName();
////                file = File.createTempFile(classFullName.substring(classFullName.lastIndexOf(".")), ".pdf", dir);
//                file = new File("/Volumes/Work/other/" + System.currentTimeMillis() + ".pdf");
//                OutputStream fos = new FileOutputStream(file);
//                fos.write(bos.toByteArray());
//                fos.flush();
//                fos.close();
//                bos.close();
//            }
//
//        } catch (Exception e) {
//        }
//    }
}
